package com.beeantec.jnrerc.modules.member.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.beeantec.jnrerc.core.api.ApiError;
import com.beeantec.jnrerc.core.api.enums.CommonState;
import com.beeantec.jnrerc.core.constants.CacheKey;
import com.beeantec.jnrerc.core.constants.ConstantsMsg;
import com.beeantec.jnrerc.core.constants.MqConstants;
import com.beeantec.jnrerc.core.enums.SmsTypeEnum;
import com.beeantec.jnrerc.core.exception.ServiceException;
import com.beeantec.jnrerc.core.utils.*;
import com.beeantec.jnrerc.dto.MemberVo;
import com.beeantec.jnrerc.dto.response.BindRespDTO;
import com.beeantec.jnrerc.dto.response.SmsCheckRespDTO;
import com.beeantec.jnrerc.entity.Member;
import com.beeantec.jnrerc.mapper.MemberMapper;
import com.beeantec.jnrerc.modules.common.service.MqService;
import com.beeantec.jnrerc.modules.common.service.SmsService;
import com.beeantec.jnrerc.modules.common.service.WxService;
import com.beeantec.jnrerc.modules.member.service.MemberService;
import com.beeantec.jnrerc.modules.shiro.jwt.JwtUtils;
import com.beeantec.jnrerc.modules.user.service.MemberRoleService;
import com.google.gson.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;

import java.net.URL;
import java.text.MessageFormat;
import java.util.List;

@Service
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService {
    protected Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    RedisUtils redisUtils;

    @Autowired
    SmsService smsService;

    @Autowired
    WxService wxService;

    @Autowired
    MqService mqService;

    @Autowired
    MemberRoleService memberRoleService;

    @Override
    public MemberVo getByPhone(String phone) {
        MemberVo memberVo = new MemberVo();
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(Member::getPhone,phone);
        Member member = baseMapper.selectOne(queryWrapper);
        if (null!=member){
            BeanUtils.copyProperties(member,memberVo);
        }
        return memberVo;
    }

    @Override
    public MemberVo getByOpenId(String openId) {
        MemberVo memberVo = new MemberVo();
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(Member::getWxOpenid,openId);
        Member  member = baseMapper.selectOne(queryWrapper);
        if (null!=member){
            BeanUtils.copyProperties(member,memberVo);
        }
        return memberVo;
    }

    @Override
    public boolean updateId(String loginType, Integer memberId, String id, String avatarUrl, String nickName) {
        Member member = baseMapper.selectById(memberId);
        member.setMemberId(memberId);
        MemberVo info =new MemberVo();
        BeanUtils.copyProperties(member, info);
        if (loginType.equals("wx")) {
            String wxUserInfoKey = MessageFormat.format(CacheKey.member_wxUserInfo, id);
            JsonObject userInfo = GsonUtils.fromJson(redisUtils.get(wxUserInfoKey).toString(), JsonObject.class);
            String openid = userInfo.get("openid").getAsString();
            member.setWxOpenid(openid);
            member.setWxUnionid(userInfo.get("unionid").getAsString());
            member.setGender(userInfo.get("sex").getAsInt());
            String headimgurl = userInfo.get("headimgurl").getAsString();
            try {
                URL url = new URL(headimgurl);
                String http = url.toURI().getScheme();
                if ("http".equals(http)) {
                    headimgurl.replace("http", "https");
                }
            } catch (Exception e) {
                log.error("{}", e);
            }
            log.info("[headimgurl:{}]", headimgurl);
            member.setAvatarUrl(headimgurl);
            member.setNickName(userInfo.get("nickname").getAsString());
        }
        int result = baseMapper.updateById(member);
        if (result==0) {
            return false;
        }
        return true;
    }

    @Override
    public BindRespDTO wxBindPhone(String id, String phone, String sms) {
        BindRespDTO bindRespDTO = new BindRespDTO();
        //绑定手机号
            SmsCheckRespDTO checkSmsResult = smsService.checkSmsCode(SmsTypeEnum.BIND.getCode(), phone, sms);
            if (!checkSmsResult.isSuccess()) {
                return null;
            }
            //验证该手机号是否被绑定
            boolean  checkPhoneResult = checkHasBind( phone, id);
            if (checkPhoneResult) {
                bindRespDTO.setSuccess(false);
                bindRespDTO.setMsg(ConstantsMsg.phone_hasBound);
                return bindRespDTO;
            }
            //绑定/注册
            bindRespDTO = bindPhone("wx", id, phone);
            if (!bindRespDTO.isSuccess()) {
                return bindRespDTO;
            }
            redisUtils.del(MessageFormat.format(CacheKey.member_wxUserInfo, id));
            return bindRespDTO;
    }

    @Override
    public BindRespDTO bindWechat(String id, String phone) {
        BindRespDTO bindRespDTO = new BindRespDTO();
        String wxUserInfoKey = MessageFormat.format(CacheKey.member_wxUserInfo, id);
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(Member::getPhone,phone);
        Member member =baseMapper.selectOne(queryWrapper);
        if (!ObjectUtils.isEmpty(id)) {
            //授权
            JsonObject tokenResult = wxService.getAccessToken(id);
            if (null==tokenResult) {
                bindRespDTO.setSuccess(false);
                bindRespDTO.setMsg(ConstantsMsg.wx_auth_fail);
                return bindRespDTO;
            }
            if (!member.getWxOpenid().isEmpty()){
                bindRespDTO.setSuccess(false);
                bindRespDTO.setMsg("手机号已绑定其他微信");
                return bindRespDTO;
            }
            String openid = tokenResult.get("openid").getAsString();
            //微信个人资料
            String accessToken = tokenResult.get("access_token").getAsString();
            JsonObject userResult = wxService.getUserInfo(accessToken, openid);
            if (null==userResult) {
                bindRespDTO.setSuccess(false);
                bindRespDTO.setMsg(ConstantsMsg.wx_auth_fail);
                return bindRespDTO;
            }
            member.setWxOpenid(openid);
            int result = baseMapper.updateById(member);
            if (result!=0){
                redisUtils.set(wxUserInfoKey, userResult.toString(), 7200);
                bindRespDTO.setSuccess(true);
                bindRespDTO.setMsg("绑定微信成功");
                return bindRespDTO;
            }
        }
        bindRespDTO.setSuccess(false);
        bindRespDTO.setMsg("绑定微信失败");
        return bindRespDTO;
    }

    @Override
    public MemberVo token(String token) {

        // 获得会话
        String memberId = JwtUtils.getMemberId(token);

        // 校验结果
        boolean check = JwtUtils.verify(token, memberId);


        if(!check){
            throw new ServiceException(ApiError.ERROR_90010001);
        }

        QueryWrapper<Member> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Member::getMemberId, Integer.parseInt(memberId));

        Member member = this.getOne(wrapper, false);
        if(member == null){
            throw new ServiceException(ApiError.ERROR_10010002);
        }

        // 被禁用
        if(member.getState().equals(CommonState.ABNORMAL)){
            throw new ServiceException(ApiError.ERROR_90010005);
        }

        return this.setToken(member);
    }

    @Override
    public MemberVo setToken(MemberVo memberVo) {
            String token = JwtUtils.sign(memberVo.getMemberId().toString());
            memberVo.setToken(token);

            // 填充角色
            List<String> roles = memberRoleService.listRoles(memberVo.getMemberId().toString());
            memberVo.setRoleIds(roles);

            return memberVo;

    }

    public boolean checkHasBind( String phone, String id) {
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(Member::getPhone,phone);
        Member memberVo = baseMapper.selectOne(queryWrapper);
        if (!ObjectUtils.isEmpty(memberVo)) {
                String wxOpenid = memberVo.getWxOpenid();
                if (!ObjectUtils.isEmpty(wxOpenid) && !id.equals(wxOpenid)) {
                    return false;
                }
            }
        return true;
        }

    public BindRespDTO bindPhone(String loginType, String id, String phone) {
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(Member::getPhone,phone);
        Member member = baseMapper.selectOne(queryWrapper);
        BindRespDTO respDTO = new BindRespDTO();
        if (ObjectUtils.isEmpty(member)) {
            MemberVo vo  = register(loginType, id, phone);
            if (null==vo) {
                respDTO.setSuccess(false);
                respDTO.setMsg("绑定注册手机号失败");
                return respDTO;
            }
        } else {
                member.setWxOpenid(id);
                int result = baseMapper.updateById(member);
                if (result==0) {
                    respDTO.setSuccess(false);
                    respDTO.setMsg("绑定手机号失败");
                    return respDTO;
                }
        }
        respDTO.setSuccess(true);
        respDTO.setMsg("绑定手机号成功");
        return respDTO;
    }


    @Override
    public MemberVo register(String loginType, String id, String phone) {
        MemberVo memberVo = new MemberVo();
        Member member = new Member();
        member.setPhone(phone);
        member.setIdentifier(DigestUtils.md5DigestAsHex((phone + "JNRERC").getBytes()));
        if (loginType.equals("wx")) {
            String wxUserInfoKey = MessageFormat.format(CacheKey.member_wxUserInfo, id);
            JsonObject userInfo = GsonUtils.fromJson(redisUtils.get(wxUserInfoKey).toString(), JsonObject.class);
            member.setWxOpenid(userInfo.get("openid").getAsString());
            member.setWxUnionid(userInfo.get("unionid").getAsString());
            member.setGender(userInfo.get("sex").getAsInt());
            member.setNickName(userInfo.get("nickname").getAsString());
            String headimgurl = userInfo.get("headimgurl").getAsString();
            try {
                URL url = new URL(headimgurl);
                String http = url.toURI().getScheme();
                if ("http".equals(http)) {
                    headimgurl.replace("http", "https");
                }
            } catch (Exception e) {
                log.error("{}", e);
            }
            log.info("[headimgurl:{}]", headimgurl);
            member.setAvatarUrl(headimgurl);
        }else {
            member.setAvatarUrl("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F201912%2F25%2F20191225224833_zloky.thumb.400_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1641902995&t=09ba927bbe11e3cb3c37d2d71ccd6c2f");
            member.setNickName("用户" + RandomUtils.getRandom(4) + phone.substring(phone.length() - 4));
        }
        int result = baseMapper.insert(member);
        if (result!=0) {
            JsonObject msg = new JsonObject();
            msg.addProperty("type", "im");
            msg.addProperty("memberId", member.getMemberId());
            mqService.push(MqConstants.member_conf_exchange, MqConstants.member_conf_routingkey, GsonUtils.toJson(msg));
            BeanUtils.copyProperties(member,memberVo);
            return memberVo;
        }
        return null;
    }

    /**
     * 保存会话信息
     * @param member
     * @return
     */
    private MemberVo setToken(Member member){

        MemberVo memberVo = new MemberVo();
        BeanMapper.copy(member, memberVo);

        // 生成Token
        String token = JwtUtils.sign(member.getMemberId().toString());
        memberVo.setToken(token);

        // 填充角色
        List<String> roles = memberRoleService.listRoles(member.getMemberId().toString());
        memberVo.setRoleIds(roles);

        return memberVo;
    }

}